﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Communication.Net.Base;

namespace UtilZ.Dotnet.Ex.Communication.Net.Web
{
    /// <summary>
    /// Websocket中间件
    /// </summary>
    public class WebsocketMiddleware : MiddlewareAbs
    {
        private readonly Func<HttpRequest, bool> _validateWebsocket;
        private readonly Action<WebSocketClient> _outputWebsocket;

        /// <summary>
        /// 获取或设置websocket文本编码器
        /// </summary>
        public Encoding WebsocketTextEncoding { get; set; } = Encoding.UTF8;

        /// <summary>
        /// 构造函数
        /// </summary>
        public WebsocketMiddleware(Func<HttpRequest, bool> validateWebsocket, Action<WebSocketClient> outputWebsocket)
            : base()
        {
            if (validateWebsocket == null)
            {
                throw new ArgumentNullException(nameof(validateWebsocket));
            }

            if (outputWebsocket == null)
            {
                throw new ArgumentNullException(nameof(outputWebsocket));
            }

            this._validateWebsocket = validateWebsocket;
            this._outputWebsocket = outputWebsocket;
        }



        /// <summary>
        /// 尝试调用中间件处理[已处理返回true,否则返回false]
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response">http响应</param>
        /// <returns>已处理返回true,否则返回false</returns>
        protected override bool PrimitiveTryInvoke(HttpRequest request, out IHttpResponse response)
        {
            response = null;

            string upgrade;
            if (!request.Headers.TryGetValue(HttpRequestHeaders.Upgrade, out upgrade))
            {
                //没有请求升级为websocket头
                return false;
            }


            //验证websocket是否符合业务场景
            if (!this._validateWebsocket(request))
            {
                //response.StatusCode = HttpStatusCodes.Forbidden;
                //return true;
                return false;
            }

            response = new HttpResponse(request.Connection);
            //检查websocket关键头信息
            if (!request.Headers.TryGetValue(HttpRequestHeaders.SecWebSocketKey, out var key))
            {
                response.StatusCode = HttpStatusCodes.NotImplemented;
                return true;
            }

            //生成头响应
            string secWebSocketAccept = this.CalSecWebSocketAccept(key);
            var headers = new Dictionary<string, string>();
            headers.Add(HttpResponseHeaders.Connection, HttpResponseHeaders.Upgrade);
            headers.Add(HttpResponseHeaders.SecWebSocketAccept, secWebSocketAccept);
            headers.Add(HttpResponseHeaders.Upgrade, "websocket");

            response = new HttpResponse(request.Connection, headers)
            {
                StatusCode = HttpStatusCodes.SwitchingProtocols
            };

            //升级为了websocket
            var initPara = new TcpClientInitPara(new WebSocketUnpacker(), request.LinkInfo.RemoteEndPoint);
            var webSocket = new WebSocketClient(request.LinkInfo, request.Stream, initPara, this.WebsocketTextEncoding);
            this._outputWebsocket(webSocket);
            return true;
        }

        private string CalSecWebSocketAccept(string key)
        {
            string str = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            byte[] buffer = Encoding.UTF8.GetBytes(str);
            var sha1 = System.Security.Cryptography.SHA1.Create();
            byte[] hashBuffer = sha1.ComputeHash(buffer);
            return Convert.ToBase64String(hashBuffer);
        }
    }
}
